import os
import subprocess
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog
from PIL import Image, ImageTk
import cv2
from tkinter import ttk
import threading

class VideoCropper:
    def __init__(self, root):
        self.root = root
        self.root.title("Video Cropper")
        self.root.geometry("743x763")  # 设置页面大小为743*573
        self.video_path = ""
        self.video_info = {}
        self.cap = None
        self.frame = None
        self.current_frame_index = 0

        # 添加占位符图像
        self.placeholder_image = Image.open("bin\\placeholder.png")
        self.placeholder_image = self.placeholder_image.resize((640, 360), Image.Resampling.LANCZOS)
        self.placeholder_image = ImageTk.PhotoImage(self.placeholder_image)

        self.create_widgets()

    def create_widgets(self):
        self.select_button = tk.Button(self.root, text="选择课程视频", command=self.select_video)
        self.select_button.pack()

        self.info_label = tk.Label(self.root, text="课程视频信息: ")
        self.info_label.pack()

        self.preview_label = tk.Label(self.root, image=self.placeholder_image)  # 设置占位符图像
        self.preview_label.pack()

        self.slider = tk.Scale(self.root, from_=0, to=100, orient=tk.HORIZONTAL, command=self.update_preview, length=723)  # 进度条横向占满
        self.slider.pack()

        self.position_label = tk.Label(self.root, text="当前位置: 00:00:00")
        self.position_label.pack()

        self.output_name_label = tk.Label(self.root, text="输出视频名称:")
        self.output_name_label.pack()

        self.output_name_entry = tk.Entry(self.root)
        self.output_name_entry.pack()
        self.output_name_entry.insert(0, "output")  # 默认输出文件名，不带扩展名

        self.crop_button = tk.Button(self.root, text="裁剪并合并", command=self.start_crop_video)
        self.crop_button.pack()

        self.console = tk.Text(self.root, height=10, width=80, bg="black", fg="white")  # 设置黑底白字
        self.console.pack()

    def select_video(self):
        self.video_path = filedialog.askopenfilename(filetypes=[("Video files", "*.mp4 *.avi *.mkv")])
        if self.video_path:
            self.get_video_info()
            self.update_preview(0)

    def get_video_info(self):
        self.cap = cv2.VideoCapture(self.video_path)
        if not self.cap.isOpened():
            messagebox.showerror("错误", "无法打开视频文件")
            return

        self.video_info['resolution'] = f"{int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))}x{int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))}"
        self.video_info['fps'] = self.cap.get(cv2.CAP_PROP_FPS)
        self.video_info['length'] = self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.video_info['fps']
        self.video_info['length_str'] = self.seconds_to_hms(self.video_info['length'])

        self.slider.config(to=int(self.video_info['length']))
        self.info_label.config(text=f"视频信息: 分辨率: {self.video_info['resolution']}, 帧率: {self.video_info['fps']}, 长度: {self.video_info['length_str']}")

    def update_preview(self, value):
        if not self.cap:
            return

        self.current_frame_index = int(float(value) * self.video_info['fps'])
        self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.current_frame_index)
        ret, frame = self.cap.read()
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame = Image.fromarray(frame)
            frame = frame.resize((640, 360), Image.Resampling.LANCZOS)  # 调整预览图像大小
            self.frame = ImageTk.PhotoImage(frame)
            self.preview_label.config(image=self.frame)

        current_time = self.current_frame_index / self.video_info['fps']
        self.position_label.config(text=f"当前位置: {self.seconds_to_hms(current_time)}")

    def start_crop_video(self):
        threading.Thread(target=self.crop_video).start()

    def crop_video(self):
        if not self.video_path:
            messagebox.showerror("错误", "请先选择视频文件")
            return

        start_time = self.current_frame_index / self.video_info['fps']
        start_time_str = self.seconds_to_hms(start_time)
        end_time_str = self.video_info['length_str']
        cut_folder = os.path.join(os.getcwd(), "video", "cut")
        os.makedirs(cut_folder, exist_ok=True)
        output_path = os.path.join(cut_folder, os.path.basename(self.video_path).split('.')[0] + ".ts")

        ffmpeg_path = os.path.join(os.getcwd(), "bin", "ffmpeg", "bin", "ffmpeg.exe")
        command = [
            ffmpeg_path,
            "-i", self.video_path,
            "-ss", start_time_str,
            "-to", end_time_str,
            "-c", "copy",  # 使用 -c 选项来指定编解码器
            output_path
        ]

        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf-8')
        for line in process.stdout:
            self.root.after(0, self.console.insert, tk.END, line)
            self.root.after(0, self.console.see, tk.END)

        self.merge_and_transcode(output_path)

    def merge_and_transcode(self, cropped_video_path):
        fixed_video_path = os.path.join(os.getcwd(), "video", "pt.ts")
        output_folder = os.path.join(os.getcwd(), "video", "output")
        os.makedirs(output_folder, exist_ok=True)
        output_name = self.output_name_entry.get()
        output_path = os.path.join(output_folder, f"{output_name}.mp4")

        # 获取pt.ts的码率和帧率
        fixed_video_info = self.get_video_info_from_path(fixed_video_path)
        cropped_video_info = self.get_video_info_from_path(cropped_video_path)

        if fixed_video_info['fps'] != cropped_video_info['fps'] or fixed_video_info['bitrate'] != cropped_video_info['bitrate']:
            # 转码成和pt.ts相同的码率和帧率
            temp_output_path = os.path.join(output_folder, f"{output_name}_temp.mp4")
            self.transcode_video(cropped_video_path, temp_output_path, fixed_video_info['fps'], fixed_video_info['bitrate'])
            cropped_video_path = temp_output_path

        ffmpeg_path = os.path.join(os.getcwd(), "bin", "ffmpeg", "bin", "ffmpeg.exe")
        command = [
            ffmpeg_path,
            "-i", fixed_video_path,
            "-i", cropped_video_path,
            "-filter_complex", "[0:v:0][0:a:0][1:v:0][1:a:0]concat=n=2:v=1:a=1[outv][outa]",
            "-map", "[outv]",
            "-map", "[outa]",
            "-c:v", "libx264",
            "-c:a", "aac",
            output_path
        ]

        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf-8')
        for line in process.stdout:
            self.root.after(0, self.console.insert, tk.END, line)
            self.root.after(0, self.console.see, tk.END)

        messagebox.showinfo("成功", "视频裁剪并合并成功")

    def get_video_info_from_path(self, video_path):
        cap = cv2.VideoCapture(video_path)
        if not cap.isOpened():
            messagebox.showerror("错误", "无法打开视频文件")
            return

        video_info = {}
        video_info['fps'] = cap.get(cv2.CAP_PROP_FPS)
        video_info['bitrate'] = cap.get(cv2.CAP_PROP_BITRATE)
        cap.release()
        return video_info

    def transcode_video(self, input_path, output_path, target_fps, target_bitrate):
        ffmpeg_path = os.path.join(os.getcwd(), "bin", "ffmpeg", "bin", "ffmpeg.exe")
        command = [
            ffmpeg_path,
            "-i", input_path,
            "-r", str(target_fps),
            "-b:v", str(target_bitrate),
            output_path
        ]

        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf-8')
        for line in process.stdout:
            self.root.after(0, self.console.insert, tk.END, line)
            self.root.after(0, self.console.see, tk.END)

    def seconds_to_hms(self, seconds):
        hours = int(seconds // 3600)
        minutes = int((seconds % 3600) // 60)
        seconds = int(seconds % 60)
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"

if __name__ == "__main__":
    root = tk.Tk()
    app = VideoCropper(root)
    root.mainloop()
